package com.anjiplus.template.gaea.business.modules.datasource.service.impl;

import com.anjiplus.template.gaea.business.modules.datasource.controller.dto.DataSourceDto;
import com.anjiplus.template.gaea.business.modules.datasource.service.OpcUaService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
import org.eclipse.milo.opcua.sdk.client.api.identity.IdentityProvider;
import org.eclipse.milo.opcua.sdk.client.api.identity.UsernameProvider;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.springframework.stereotype.Service;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class OpcUaServiceImpl implements OpcUaService {

    @Override
    public OpcUaClient createClient(DataSourceDto dto) throws Exception {
        String endpointUrl = dto.getOpcuaUrl();
        String username = dto.getUsername();
        String password = dto.getPassword();

        Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
        Files.createDirectories(securityTempDir);
        if (!Files.exists(securityTempDir)) {
            throw new Exception("unable to create security dir: " + securityTempDir);
        }
        IdentityProvider identityProvider;
        //判断用户名密码，没有的话，则为匿名登录
        if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {
            identityProvider = new UsernameProvider(username, password);
        } else {
            identityProvider = new AnonymousProvider();
        }
        OpcUaClient opcUaClient =  OpcUaClient.create(endpointUrl,
                endpoints ->
                        endpoints.stream()
                                .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
                                .findFirst(),
                configBuilder ->
                        configBuilder
                                .setApplicationName(LocalizedText.english("eclipse milo opc-ua client"))
                                .setApplicationUri("urn:eclipse:milo:examples:client")
                                //访问方式
                                .setIdentityProvider(identityProvider)
                                .setRequestTimeout(UInteger.valueOf(4000))
                                .build()
        );
//        Thread.sleep(2000); // 线程休眠一下再返回对象，给创建过程一个时间。

        return opcUaClient;
    }

    @Override
    public Map<String, String> readNodeValues(DataSourceDto dto,List<String> identifiers) throws Exception {
        Map<String, String> map = new HashMap<>();
        OpcUaClient uaClient = createClient(dto);
        uaClient.connect().get();

        if (identifiers != null) {
            identifiers.forEach(iden -> {
                //节点
                NodeId nodeId = new NodeId(2, iden);
                //读取节点数据
                try {
                    DataValue value = uaClient.readValue(0.0, TimestampsToReturn.Neither, nodeId).get();
                    if (value != null && value.getValue() != null && value.getValue().getValue() != null) {
                        map.put(iden,value.getValue().getValue().toString());
                    }else{
                        map.put(iden,"");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        //释放连接
        if(uaClient != null){
            uaClient.disconnect();
        }
        return map;
    }

}
